﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using Microsoft.ResourceManagement.Samples.ResourceManagementClient;
using Microsoft.ResourceManagement.Samples.ResourceManagementClient.ResourceManagement;
using Microsoft.ResourceManagement.Utilities;
using Microsoft.ResourceManagement.WebServices.WSResourceManagement;
using Microsoft.ResourceManagement.Workflow.Activities;

namespace Ensynch.ILM2.Workflow.Activities
{
    public partial class GenerateOIDActivity : SequenceActivity
    {
        public RequestType CurrentRequest;
        public Guid TargetId;

        public GenerateOIDActivity()
        {
            InitializeComponent();
        }

        #region Class Properties

        public static DependencyProperty TheActivityNameProperty =
            DependencyProperty.Register("TheActivityName", typeof(string), typeof(GenerateOIDActivity));

        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Category("Properties")]
        public string TheActivityName
        {
            get { return (string)this.GetValue(GenerateOIDActivity.TheActivityNameProperty); }
            set
            {
                this.SetValue(GenerateOIDActivity.TheActivityNameProperty, value);
            }
        }

        #endregion

        #region Class Methods

        private void _calculateOID(object sender, EventArgs e)
        {
            // Only operate on Create requests
            if (CurrentRequest.Operation != OperationType.Create)
            {
                return;
            }

            // Create the list of UpdateParameters
            List<UpdateRequestParameter> updateParameters = new List<UpdateRequestParameter>();

            // Always set isDefunct to true
            updateParameters.Add(
                new UpdateRequestParameter("isDefunct", UpdateMode.Modify, false));

            /// Determine the parent type; hierarchy is:
            /// oidBase
            ///    |
            ///    +- oidNode
            ///           |
            ///           +- oidAllocation
            bool shouldGetNewOID = false;
            string parentType = null;
            string parentPointer = null;
            switch (CurrentRequest.TargetObjectType)
            {
                case "oidNode":
                    shouldGetNewOID = true;
                    parentType = "oidBase";
                    parentPointer = "baseOID";
                    break;
                case "oidAllocation":
                    shouldGetNewOID = true;
                    parentType = "oidNode";
                    parentPointer = "nodeOID";
                    break;
                default:
                    shouldGetNewOID = false;
                    break;
            }

            if (shouldGetNewOID)
            {
                // Extract the parent OID from the request parameters
                ReadOnlyCollection<CreateRequestParameter> requestParameters = 
                    CurrentRequest.ParseParameters<CreateRequestParameter>();
                string parentOID = null;
                foreach (CreateRequestParameter requestParameter in requestParameters)
                {
                    if (requestParameter.PropertyName == parentPointer)
                    {
                        parentOID = requestParameter.Value.ToString();
                        break;
                    }
                }

                if (parentOID == null)
                {
                    throw new ArgumentNullException(parentPointer);
                }

                // Define the search filter
                string filter = "/" + CurrentRequest.TargetObjectType + "[" +
                    parentPointer + " = '" + parentOID + "']";

                // Tell the enumeration to sort by and return only attributeID
                List<string> selectionAttributes = null;
                List<string> sortingAttributes = null;
                selectionAttributes = new List<string> {
                    "attributeID"
                };
                sortingAttributes = new List<string> {
                    "attributeID"
                };

                IList<ResourceManagementObject> items = null;
                WSEnumerationClient enumerationClient = new WSEnumerationClient();
                enumerationClient.Enumerate(filter, selectionAttributes, sortingAttributes);
                if (enumerationClient.IsContextValid)
                {
                    // Pull only the last item to get the last index
                    items = enumerationClient.Pull(
                        enumerationClient.NumItems - 1, enumerationClient.NumItems);
                }

                // Find the next available index; hard-code the starting index to 1
                int nextIndex = 1;
                if (items == null)
                {
                    // Assume no objects exist yet
                }
                else if (items.Count > 1)
                {
                    throw new InvalidOperationException("Unexpected pull response");
                }
                else if (items.Count == 1)
                {
                    int currentIndex;
                    if (items[0].AttributeNames.Contains("attributeID") &&
                        items[0]["attributeID"].AttributeSingleValue != null &&
                        int.TryParse(items[0]["attributeID"].AttributeSingleValue.ToString(), out currentIndex))
                    {
                        nextIndex = currentIndex + 1;
                    }
                }

                // Verify that the OID we found is indeed free
                filter = "/" + CurrentRequest.TargetObjectType + "[(" +
                    parentPointer + " = '" + parentOID + "') and (" +
                    "attributeID = '" + nextIndex + "')]";
                items = null;
                enumerationClient = new WSEnumerationClient();
                enumerationClient.Enumerate(filter, selectionAttributes, sortingAttributes);
                if (enumerationClient.NumItems > 0)
                {
                    throw new InvalidOperationException("Assertion failed: OID not available");
                }

                // Add the new OID to the update parameters
                updateParameters.Add(
                    new UpdateRequestParameter("attributeID", UpdateMode.Modify, nextIndex));
            }

            // Finally, assign the update parameters to the UpdateResourceActivity
            UpdateTarget.UpdateParameters = updateParameters.ToArray();

            // Don't forget to set the Target ID
            TargetId = CurrentRequest.Target.GetGuid();
        }

        private void _updateParametersNotNull(object sender, ConditionalEventArgs e)
        {
            e.Result = UpdateTarget.UpdateParameters != null;
        }

        #endregion


    }
}
